// Proposal.csr
//
// Copyright (c) 2007 Mike Strobel
//
// This source code is subject to the terms of the Microsoft Reciprocal License (Ms-RL).
// For details, see <http://www.opensource.org/licenses/ms-rl.html>.
//
// All other rights reserved.

using System;
using System.Linq;
using System.Collections.Generic;

using Supremacy.Collections;
using Supremacy.Entities;
using Supremacy.Game;
using Wintellect.PowerCollections;

namespace Supremacy.Diplomacy
{
    [Serializable]
    public class Proposal
    {
        private int _senderId;
        private int _recipientId;
        private readonly ArrayList<Stipulation> _offerStipulations;
        private readonly ArrayList<Stipulation> _demandStipulations;
        private Proposal _originalProposal;

        public Proposal()
        {
            _offerStipulations = new ArrayList<Stipulation>();
            _demandStipulations = new ArrayList<Stipulation>();
        }

        public Proposal(Civilization sender, Civilization recipient) : this()
        {
            if (sender == null)
                throw new ArgumentNullException("sender");
            if (recipient == null)
                throw new ArgumentNullException("recipient");
            _senderId = sender.CivID;
            _recipientId = recipient.CivID;
        }

        public Proposal(Civilization sender, Civilization recipient, Proposal originalProposal)
            : this(sender, recipient)
        {
            if (originalProposal == null)
                throw new ArgumentNullException("originalProposal");
            _originalProposal = originalProposal;
        }

        public Civilization Sender
        {
            get { return GameContext.Current.Civilizations[_senderId]; }
            set { _senderId = (value != null) ? value.CivID : Civilization.InvalidID; }
        }

        public Civilization Recipient
        {
            get { return GameContext.Current.Civilizations[_recipientId]; }
            set { _recipientId = (value != null) ? value.CivID : Civilization.InvalidID; }
        }

        public IList<Stipulation> OfferStipulations
        {
            get { return Algorithms.ReadOnly(_offerStipulations); }
        }

        public IList<Stipulation> DemandStipulations
        {
            get { return Algorithms.ReadOnly(_demandStipulations); }
        }

        public IList<Stipulation> AllStipulations
        {
            get { return Algorithms.ReadOnly(_offerStipulations.Union(_demandStipulations).ToList()); }
        }

        public bool IsCounterOffer
        {
            get { return (_originalProposal != null); }
        }

        public bool IsGift
        {
            get
            {
                if ((_offerStipulations.Count == 0) || (_demandStipulations.Count != 0))
                {
                    return false;
                }
                foreach (Stipulation stipulation in _offerStipulations)
                {
                    if (!(stipulation is GiftStipulation))
                        return false;
                }
                return true;
            }
        }

        public bool IsDemand
        {
            get
            {
                if ((_offerStipulations.Count != 0) || (_demandStipulations.Count == 0))
                {
                    return false;
                }
                foreach (Stipulation demand in DemandStipulations)
                {
                    if (demand.IsMutual)
                    {
                        return false;
                    }
                }
                return true;
            }
        }

        public Proposal OriginalProposal
        {
            get { return _originalProposal; }
            set { _originalProposal = value; }
        }

        public static Proposal CreateCounterProposal(Proposal originalProposal)
        {
            if (originalProposal == null)
                throw new ArgumentNullException("originalProposal");

            Proposal counterProposal = new Proposal(
                originalProposal.Recipient, 
                originalProposal.Sender);
            
            counterProposal.OriginalProposal = originalProposal;

            return counterProposal;
        }

        public void AddOffer(Stipulation stipulation)
        {
            if (stipulation == null)
                throw new ArgumentNullException("stipulation");
            _offerStipulations.Add(stipulation);
            RemoveRedundantStipulations(stipulation, false);
        }

        public void AddDemand(Stipulation stipulation)
        {
            if (stipulation == null)
                throw new ArgumentNullException("stipulation");
            _demandStipulations.Add(stipulation);
            RemoveRedundantStipulations(stipulation, true);
        }

        public void RemoveOffer(Stipulation stipulation)
        {
            if (stipulation != null)
                _offerStipulations.Remove(stipulation);
        }

        public void RemoveDemand(Stipulation stipulation)
        {
            if (stipulation != null)
                _demandStipulations .Remove(stipulation);
        }

        private void RemoveRedundantStipulations(Stipulation stipulation, bool isDemand)
        {
            List<Stipulation> removedStipulations = new List<Stipulation>();
            foreach (Stipulation otherStipulation in _demandStipulations)
            {
                if ((isDemand || (otherStipulation.IsMutual && stipulation.IsMutual))
                    && (stipulation != otherStipulation)
                    && stipulation.IsSupersetOf(otherStipulation)
                    && ((stipulation.IsDurationFixed && otherStipulation.IsDurationFixed)
                        || ((stipulation is TreatyStipulation) && (otherStipulation is TreatyStipulation))))
                {
                    removedStipulations.Add(otherStipulation);
                }
            }
            _demandStipulations.RemoveRange(removedStipulations);
            removedStipulations.Clear();
            foreach (Stipulation otherStipulation in _offerStipulations)
            {
                if ((!isDemand || (otherStipulation.IsMutual && stipulation.IsMutual))
                    && (stipulation != otherStipulation)
                    && stipulation.IsSupersetOf(otherStipulation)
                    && ((stipulation.IsDurationFixed && otherStipulation.IsDurationFixed)
                        || ((stipulation is TreatyStipulation) && (otherStipulation is TreatyStipulation))))
                {
                    removedStipulations.Add(otherStipulation);
                }
            }
            _offerStipulations.RemoveRange(removedStipulations);
        }
    }
}
